Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1x 1x 1x 1x 1x | import { getSession } from "@/lib/auth";
import { redirect } from "next/navigation";
import { getDb } from "@/lib/db";
import { requireCollectionOwnerPage } from "@/lib/collection-access";
import { MemberController } from "@/server/api/members";
import { InvitationController } from "@/server/api/invitations";
import { AppLayout } from "@/components/layout";
import { trail } from "@/components/layout/breadcrumb-trails";
import { Card } from "@/components/ui";
import { MemberList } from "@/features/collections/MemberList";
import { InviteForm } from "@/features/collections/InviteForm";
interface MembersPageProps {
params: Promise<{ id: string }>;
}
export default async function MembersPage({ params }: MembersPageProps) {
const { id } = await params;
const session = await getSession();
Iif (!session?.user) {
redirect("/login");
}
const db = getDb();
// Owner-only page: members:manage = owner by role (purses-yqw). The owner gate
// also covers the invitee-email PII surfaced by the pending rows below.
const collection = await requireCollectionOwnerPage(db, id, session.user.id);
const members = await MemberController.fromDb(db).listMembers(collection.id);
const invitations = await InvitationController.fromDb(db).listByCollection(collection.id);
const pending = invitations.filter((i) => i.status === "pending");
return (
<AppLayout breadcrumbs={trail.members(collection)}>
<div className="space-y-8">
<div className="space-y-2">
<h1 className="text-2xl text-ink sm:text-3xl">People</h1>
<p className="max-w-2xl text-ink-soft">
Sharing is an after-the-fact step — invite someone once your list feels ready.
</p>
</div>
<Card padding="lg">
<InviteForm collectionId={collection.id} />
</Card>
<MemberList members={members} pending={pending} canManage />
</div>
</AppLayout>
);
}
|